package me.hyman.testcustomview.circleMenu;

import android.content.Context;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.TextView;

import me.hyman.testcustomview.R;
import me.hyman.testcustomview.util.Logger;

/**
 * Created by luluteam on 2016/9/30.
 */
public class CircleMenuLayout extends ViewGroup {

    /**
     * 该容器内child item的默认尺寸（总长度的四分之一）
     */
    private static final float RADIO_DEFAULT_CHILD_DIMENSION = 1/4f;

    /**
     * 菜单的中心child的默认尺寸（总长度的三分之一）
     */
    private static final float RADIO_DEFAULT_CENTER_ITEM_DIMENSION = 1/3f;

    /**
     * 该容器的内边距,无视padding属性，如需边距请用该变量
     */
    private static final float RADIO_PADDING_LAYOUT = 1/12f;

    /**
     * 当每秒移动角度达到该值时，认为是快速移动
     */
    private static final int FLINGABLE_VALUE = 300;

    /**
     * 如果移动角度达到该值，则屏蔽点击
     */
    private static final int NOCLICK_VALUE = 3;

    private int mFlingableValue = FLINGABLE_VALUE;
    /**
     * 该容器的内边距,无视padding属性，如需边距请用该变量
     */
    private float mPadding;
    /**
     * 布局时的开始角度
     */
    private double mStartAngle = 0;
    /**
     * 菜单项的文本
     */
    private String[] mItemTexts;
    /**
     * 菜单项的图标
     */
    private int[] mItemImgs;
    /**
     * 菜单的个数
     */
    private int mMenuItemCount;
    /**
     * 检测按下到抬起时旋转的角度
     */
    private float mTmpAngles;
    /**
     * 检测按下到抬起时使用的时间
     */
    private long mDownTime;
    /**
     * 判断是否正在自动滚动
     */
    private boolean isFling;

    private int mRadius;

    private int mMenuItemLayoutResId;
    //private int mMenuItemLayoutResId = R.layout.

    public CircleMenuLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        setPadding(0, 0, 0, 0);
    }

    public void setMenuItemIconsAndTexts(int[] resIds, String[] texts) {
        if(resIds == null && texts == null) {
            throw new IllegalArgumentException("菜单项文本和图片请至少设置一项");
        }

        mItemImgs = resIds;
        mItemTexts = texts;

        mMenuItemCount = resIds==null? texts.length : resIds.length;
        if(resIds != null && texts != null) {
            mMenuItemCount = Math.min(resIds.length, texts.length);
        }

        addMenuItems();
    }

    private void addMenuItems() {

        LayoutInflater layoutInflater = LayoutInflater.from(getContext());

        for(int i=0; i<mMenuItemCount; i++) {

            final int j = i;
            View view = layoutInflater.inflate(mMenuItemLayoutResId, this, false);
            ImageView iv = (ImageView) view.findViewById(R.id.id_circle_menu_item_image);
            TextView tv = (TextView) view.findViewById(R.id.id_circle_menu_item_text);

            if(iv != null) {
                iv.setVisibility(VISIBLE);
                iv.setImageResource(mItemImgs[i]);
                iv.setOnClickListener(new OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        if(onMenuItemClickListener != null) {
                            onMenuItemClickListener.onItemClick(v, j);
                        }
                    }
                });
            }

            if(tv != null) {
                tv.setVisibility(VISIBLE);
                tv.setText(mItemTexts[i]);
            }

            addView(view);
        }
    }

    public void setMenuItemLayoutResId(int menuItemResId) {
        this.mMenuItemLayoutResId = menuItemResId;
    }

    /**
     * 设置内边距的比例
     *
     * @param mPadding
     */
    public void setPadding(float mPadding) {
        this.mPadding = mPadding;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        int resWidth = 0;
        int resHeight = 0;

        int width = MeasureSpec.getSize(widthMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);

        /**
         * 如果宽或者高的测量模式非精确值
         */
        if(widthMode != MeasureSpec.EXACTLY || heightMode != MeasureSpec.EXACTLY) {
            // 主要设置为背景图的高度
            resWidth = getSuggestedMinimumWidth();
            // 如果未设置背景图片，则设置为屏幕宽高的默认值
            resWidth = resWidth==0 ? getDefaultWidth() : resWidth;

            resHeight = getSuggestedMinimumHeight();
            resHeight = resHeight==0 ? getDefaultWidth() : resHeight;

        } else {
            // 如果都设置为精确值，则直接取小值；
            resWidth = resHeight = Math.min(width, height);
        }

        setMeasuredDimension(resWidth, resHeight);

        mRadius = Math.max(getMeasuredWidth(), getMeasuredHeight());

        int childCount = getChildCount();
        int childSize = (int) (mRadius * RADIO_DEFAULT_CHILD_DIMENSION);
        int childMode = MeasureSpec.EXACTLY;

        for(int i=0; i<childCount; i++) {
            View child = getChildAt(i);

            if(child.getVisibility() == GONE) {
                continue;
            }

            int makeMeasureSpec = -1;
            if(child.getId() == R.id.id_circle_menu_item_center) {
                makeMeasureSpec = MeasureSpec.makeMeasureSpec((int) (mRadius*RADIO_DEFAULT_CENTER_ITEM_DIMENSION), childMode);
            } else {
                makeMeasureSpec = MeasureSpec.makeMeasureSpec(childSize, childMode);
            }
            child.measure(makeMeasureSpec, makeMeasureSpec);
        }

        mPadding = RADIO_PADDING_LAYOUT * mRadius;
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {

        int layoutRadius = mRadius;

        int childCount = getChildCount();
        int childWidth = (int) (layoutRadius * RADIO_DEFAULT_CHILD_DIMENSION);
        int left, top;

        if(childCount <= 1) {
            throw new IllegalArgumentException("请至少设置一个菜单项");
        }
        // 减去centerItem
        float anglePerItem = 360 / (childCount - 1);

        for(int i=0; i<childCount; i++) {

            final View child = getChildAt(i);
            if(child.getId() == R.id.id_circle_menu_item_center || child.getVisibility() == GONE) {
                continue;
            }

            mStartAngle %= 360;
            // 计算中心点到menu item中心的距离
            float distance = layoutRadius/2f - childWidth/2 - mPadding;

            // 默认x轴正方向为0度，顺时针方向
            left = layoutRadius/2 + (int)Math.round(distance*Math.cos(Math.toRadians(mStartAngle)) - childWidth/2f);
            top = layoutRadius/2 + (int)Math.round(distance*Math.sin(Math.toRadians(mStartAngle)) - childWidth/2f);

            child.layout(left, top, left+childWidth, top+childWidth);
            mStartAngle += anglePerItem;
        }

        final View centerView = findViewById(R.id.id_circle_menu_item_center);
        if(centerView != null) {

            int cl = layoutRadius/2 - centerView.getMeasuredWidth()/2;
            centerView.layout(cl, cl, cl+centerView.getMeasuredWidth(), cl+centerView.getMeasuredWidth());

            centerView.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    if(onMenuItemClickListener != null) {
                        onMenuItemClickListener.onCenterItemClick(centerView);
                    }
                }
            });
        }
    }

    private float mLastX;
    private float mLastY;
    private AutoFlingRunnable autoFlingRunnable;

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {

        float x = ev.getX();
        float y = ev.getY();

        switch (ev.getAction()) {

            case MotionEvent.ACTION_DOWN:

                mLastX = x;
                mLastY = y;

                mDownTime = System.currentTimeMillis();
                mTmpAngles = 0;

                if(isFling) {
                    removeCallbacks(autoFlingRunnable);
                    isFling = false;

                    return true;
                }

                break;

            case MotionEvent.ACTION_MOVE:

                float start = getAngle(mLastX, mLastY);
                float end = getAngle(x, y);

                if(getQuadrant(x, y) == 1 || getQuadrant(x, y) == 4) {
                    mStartAngle += end - start;
                    mTmpAngles += end - start;
                } else {
                    mStartAngle += start - end;
                    mTmpAngles += start - end;
                }

                requestLayout();

                mLastY = x;
                mLastY = y;

                break;

            case MotionEvent.ACTION_UP:

                // 计算每秒移动的角度
                float anglePerSecond = mTmpAngles * 1000 / (System.currentTimeMillis() - mDownTime);

                // 如果达到该值认为是快速移动
                if(Math.abs(anglePerSecond) > mFlingableValue && !isFling) {
                    post(autoFlingRunnable = new AutoFlingRunnable(anglePerSecond));
                }

                // 如果当前旋转角度超过该值，则屏蔽点击
                if (Math.abs(mTmpAngles) > NOCLICK_VALUE) {
                    return true;
                }

                break;
        }
        return super.dispatchTouchEvent(ev);
    }

    /**
     * 根据触摸的位置，计算角度
     *
     * Math.sqrt( x * x + y * y )是斜边长，乘以 sin a 就是 y 的长度；
     * 反之求a的角度：即Math.asin(y / Math.hypot(x, y) ； [ hypot是x * x + y * y ]
     *
     * @param xTouch
     * @param yTouch
     * @return
     */
    private float getAngle(float xTouch, float yTouch) {
        double x = xTouch - (mRadius / 2d);
        double y = yTouch - (mRadius / 2d);
        return (float) (Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI);
    }

    /**
     * 根据当前位置计算象限
     *
     * @param x
     * @param y
     * @return
     */
    private int getQuadrant(float x, float y) {
        int tmpX = (int) (x - mRadius / 2);
        int tmpY = (int) (y - mRadius / 2);
        if (tmpX >= 0) {
            return tmpY >= 0 ? 4 : 1;
        } else {
            return tmpY >= 0 ? 3 : 2;
        }
    }

    private class AutoFlingRunnable implements Runnable {

        private float anglePerSecond;

        public AutoFlingRunnable(float velocity) {
            this.anglePerSecond = velocity;
        }

        @Override
        public void run() {

            // 如果小于20,则停止
            if(Math.abs(anglePerSecond) < 20) {
                isFling = false;
                return;
            }

            isFling = true;

            // 不断改变mStartAngle，让其滚动，/30为了避免滚动太快
            mStartAngle += anglePerSecond / 30;
            // 逐渐减小这个值
            anglePerSecond /= 1.0666f;

            postDelayed(this, 30);
            // 重新布局
            requestLayout();
        }
    }


    /**
     * 获得默认该layout的尺寸
     *
     * @return
     */
    private int getDefaultWidth() {
        WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics outMetrics = new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(outMetrics);
        return Math.min(outMetrics.widthPixels, outMetrics.heightPixels);
    }

    public interface OnMenuItemClickListener {
        void onItemClick(View view, int pos);
        void onCenterItemClick(View view);
    }

    private OnMenuItemClickListener onMenuItemClickListener;
    public void setOnMenuItemClickListener(OnMenuItemClickListener onMenuItemClickListener) {
        this.onMenuItemClickListener = onMenuItemClickListener;
    }
}
